#include "TextureManager.h"
#include <GL/glut.h>
#include <SOIL/SOIL.h>
#include "Enum.h"
#include "Game.h"
#include "Util.h"

TextureManager::TextureManager() {
	// TITLE
	loadTexture("tex/title");

	// TILE TEXTURES
	addTileTexture(DT_DUNGEON, TT_NORMAL, "tex/tile/crypt1");
	addTileTexture(DT_DUNGEON, TT_NORMAL, "tex/tile/crypt3");
	addTileTexture(DT_DUNGEON, TT_NORMAL, "tex/tile/crypt6");

	// WALL TEXTURES
	addWallTexture(DT_DUNGEON, "tex/obs/crypt0");
	addWallTexture(DT_DUNGEON, "tex/obs/crypt1");
	addWallTexture(DT_DUNGEON, "tex/obs/crypt2");
	addWallTexture(DT_DUNGEON, "tex/obs/crypt3");
	addWallTexture(DT_DUNGEON, "tex/obs/crypt4");
	addWallTexture(DT_DUNGEON, "tex/obs/crypt5");
	addWallTexture(DT_DUNGEON, "tex/obs/crypt7");
	addWallTexture(DT_DUNGEON, "tex/obs/crypt8");

	// OBJECT TEXTURES
	addObjectTexture(TH_PLAYER_TYPE, PT_DEFAULT_PLAYER, "tex/char/player"); // PLAYERS
	addObjectTexture(TH_NPC_TYPE, NT_ABOMINABLE_HORROR, "tex/char/abominable_horror"); // NPCS
	addObjectTexture(TH_NPC_TYPE, NT_ABOMINATION, "tex/char/abomination");
	addObjectTexture(TH_NPC_TYPE, NT_DEATH_FIEND, "tex/char/death_fiend");
	addObjectTexture(TH_NPC_TYPE, NT_HORRIFYING_MASS, "tex/char/horrifying_mass");
	addObjectTexture(TH_NPC_TYPE, NT_MUTANT, "tex/char/mutant");
	addObjectTexture(TH_NPC_TYPE, NT_SLIME, "tex/char/slime");
	addObjectTexture(TH_NPC_TYPE, NT_SOUL_EATER, "tex/char/soul_eater");
	addObjectTexture(TH_NPC_TYPE, NT_TENTACLED_STARSPAWN, "tex/char/tentacled_starspawn");
	addObjectTexture(TH_NPC_TYPE, NT_THRASHING_HORROR, "tex/char/thrashing_horror");
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_SHORT_SWORD, "tex/item/shortsword"); // MELEE_WEAPONS
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_LONG_SWORD, "tex/item/longsword");
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_BASTARD_SWORD, "tex/item/bastardsword");
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_TWO_HANDED_SWORD, "tex/item/2hsword");
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_CURVED_SWORD, "tex/item/curvedsword");
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_MACE, "tex/item/mace");
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_FLAIL, "tex/item/flail");
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_MORNINGSTAR, "tex/item/morningstar");
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_SHORT_SPEAR, "tex/item/shortspear");
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_LONG_SPEAR, "tex/item/longspear");
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_HALBERD, "tex/item/halbred");
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_LANCE, "tex/item/lance");
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_AXE, "tex/item/axe");
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_GREAT_AXE, "tex/item/greataxe");
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_WAR_AXE, "tex/item/waraxe");
	addObjectTexture(TH_MELEE_WEAPON_TYPE, MWT_EXECUTIONERS_AXE, "tex/item/executionersaxe");
	addObjectTexture(TH_RANGED_WEAPON_TYPE, RWT_PISTOL, "tex/item/9mm_pistol"); // RANGED_WEAPONS
	addObjectTexture(TH_POTION_TYPE, PT_HEALING, "tex/item/healing"); // POTIONS
	addObjectTexture(TH_POTION_TYPE, PT_POISON, "tex/item/poison");
	addObjectTexture(TH_POTION_TYPE, PT_INVIS, "tex/item/invis");
	addObjectTexture(TH_POTION_TYPE, PT_GAIN_ATTR, "tex/item/gainattr");
	addObjectTexture(TH_POTION_TYPE, PT_WATER, "tex/item/water");
	addObjectTexture(TH_MISC_TYPE, MT_KEY_SQUARE, "tex/item/squarekey"); // MISC
	addObjectTexture(TH_MISC_TYPE, MT_KEY_ROUND, "tex/item/roundkey");
	addObjectTexture(TH_MISC_TYPE, MT_KEY_SKELETON, "tex/item/skeletonkey");
	addObjectTexture(TH_MISC_TYPE, MT_VICTORY_ITEM, "tex/item/trophy");
	addObjectTexture(TH_TOOL_TYPE, TT_PLANT, "tex/item/plant_tools"); // TOOLS
	addObjectTexture(TH_TOOL_TYPE, TT_METAL, "tex/item/metal_tools");
	addObjectTexture(TH_FOOD_TYPE, FT_BREAD_RATION, "tex/item/bread"); // FOOD
	addObjectTexture(TH_FOOD_TYPE, FT_MEAT_RATION, "tex/item/meat");
	addObjectTexture(TH_FOOD_TYPE, FT_CORPSE, "tex/misc/blood");
	addObjectTexture(TH_INGREDIENT_TYPE, IT_HERB_PAPRIKA, "tex/item/paprikaherb"); // INGREDIENTS
	addObjectTexture(TH_INGREDIENT_TYPE, IT_HERB_PARSLEY, "tex/item/parsleyherb");
	addObjectTexture(TH_INGREDIENT_TYPE, IT_HERB_MUSHROOM, "tex/item/mushroom");
	addObjectTexture(TH_INGREDIENT_TYPE, IT_ALCH_NEWT_EYE, "tex/item/newteye");
	addObjectTexture(TH_INGREDIENT_TYPE, IT_ALCH_RAT_TAIL, "tex/item/rattail");
	addObjectTexture(TH_INGREDIENT_TYPE, IT_ALCH_GUNPOWDER, "tex/item/gunpowder");
	addObjectTexture(TH_INGREDIENT_TYPE, IT_METAL_SCRAP, "tex/item/scrap_metal");
	addObjectTexture(TH_SCROLL_TYPE, ST_IDENTIFY, "tex/item/identify"); // SCROLLS
	addObjectTexture(TH_SCROLL_TYPE, ST_UNCURSE, "tex/item/uncurse");
	addObjectTexture(TH_AMMO_TYPE, AT_9MM, "tex/item/9mm_ammo"); // AMMO
	addObjectTexture(TH_ARMOR_TYPE, AT_HEAD_ARMET, "tex/item/armet"); // ARMOR
	addObjectTexture(TH_ARMOR_TYPE, AT_BODY_LEATHER_SCALE, "tex/item/leather_scale");
	addObjectTexture(TH_ARMOR_TYPE, AT_BODY_CHAIN, "tex/item/chainmail");
	addObjectTexture(TH_ARMOR_TYPE, AT_HANDS_GAUNTLETS, "tex/item/gauntlets");
	addObjectTexture(TH_ARMOR_TYPE, AT_LEGS_LEGGINGS, "tex/item/leggings");
	addObjectTexture(TH_ARMOR_TYPE, AT_FEET_SABATONS, "tex/item/sabatons");
	addObjectTexture(TH_SHIELD_TYPE, ST_BUCKLER, "tex/item/buckler"); // SHIELDS
	addObjectTexture(TH_SHIELD_TYPE, ST_KITE, "tex/item/kite_shield");
	addObjectTexture(TH_RESOURCE_TYPE, RT_PT_PAPRIKA, "tex/obs/paprikaplant"); // RESOURCES
	addObjectTexture(TH_RESOURCE_TYPE, RT_PT_PARSLEY, "tex/obs/parsleyplant");
	addObjectTexture(TH_RESOURCE_TYPE, RT_PT_MUSHROOM, "tex/obs/mushroomplant");
	addObjectTexture(TH_RESOURCE_TYPE, RT_MT_SCRAP, "tex/obs/scrappile");
	addObjectTexture(TH_ITEMCONTAINER_TYPE, ICT_BOX, "tex/obs/box"); // ITEM CONTAINERS
	addObjectTexture(TH_ITEMCONTAINER_TYPE, ICT_CHEST, "tex/obs/chest");
	addObjectTexture(TH_ITEMCONTAINER_TYPE, ICT_POTTERY, "tex/obs/pottery");
	addObjectTexture(TH_TRAP_TYPE, TT_DAGGER, "tex/obs/daggertrap"); // TRAPS
	addObjectTexture(TH_GENERIC_TYPE, GT_OB_DOOR, "tex/obs/door_open"); // GENERICS
	addObjectTexture(TH_GENERIC_TYPE, GT_OB_DOOR, "tex/obs/door_closed");
	m_objectTextures[TH_GENERIC_TYPE][GT_OB_WALL].push_back(0);
	addObjectTexture(TH_GENERIC_TYPE, GT_OB_PORTAL, "tex/obs/stairs_up");
	addObjectTexture(TH_GENERIC_TYPE, GT_OB_PORTAL, "tex/obs/stairs_down");
}

TextureManager::~TextureManager() {
	GLuint* textures = new GLuint[m_textures.size()];
	for(unsigned int i = 0; i < m_textures.size(); i++) {
		textures[i] = m_textures[i];
	}
	glDeleteTextures(m_textures.size(), textures);
	m_tileTextures.clear();
	m_wallTextures.clear();
	m_objectTextures.clear();
	m_textures.clear();
}

void TextureManager::addTileTexture(DungeonType dungeonType, TileType tileType, std::string filename) {
	m_tileTextures[dungeonType][tileType].push_back(loadTexture(filename));
}

void TextureManager::addWallTexture(DungeonType dungeonType, std::string filename) {
	m_wallTextures[dungeonType].push_back(loadTexture(filename));
}

void TextureManager::addObjectTexture(TypeHierarchy category, int type, std::string filename) {
	m_objectTextures[category][type].push_back(loadTexture(filename));
}

unsigned int TextureManager::loadTexture(std::string filename) {
	unsigned int texture = SOIL_load_OGL_texture((g_currDirectory + filename + ".png").c_str(), SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);
	m_textures.push_back(texture);
	return texture;
}

int TextureManager::convertIndex(unsigned int size, int x, int y) {
	int n=(int)x+(int)y*57;
	n=(n<<13)^n;
	int nn=(n*(n*n*60493+19990303)+1376312589)&0x7fffffff;
	return int(double(nn)/(1073741824.0*2.0)*size);
}

unsigned int TextureManager::getTileTexture(DungeonType dungeonType, TileType tileType, int x, int y) const {
	return m_tileTextures.at(dungeonType).at(tileType).at(convertIndex(m_tileTextures.at(dungeonType).at(tileType).size(), x, y));
}
unsigned int TextureManager::getObjectTexture(TypeHierarchy category, int type, int index) const {
	return m_objectTextures.at(category).at(type).at(index);
}
unsigned int TextureManager::getWallTexture(DungeonType dungeonType, int x, int y) const {
	return m_wallTextures.at(dungeonType).at(convertIndex(m_wallTextures.at(dungeonType).size(), x, y));
}
unsigned int TextureManager::getTexture(int i) const {
	return m_textures.at(i);
}
